package com.bjpowernode.springboot;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

/**
 * @Author: yg
 * @create 2025-01-18 - 21:33
 * @
 */
public class Tetris extends JPanel {
    private Tetromino currentOne = Tetromino.RandomOn();
    private Tetromino nextOne = Tetromino.RandomOn();
    private Cell[][] wall = new Cell[16][9];
    private static String imgPath = "E:\\app_cache\\AppShare\\idea_workspace\\snakeLikeFood\\src\\main\\java\\com\\bjpowernode\\springboot\\Images\\";
    private static final int CELL_SIZE = 48;
    int[] score_pool = {0, 1, 2, 5, 10};
    private int total_score = 0;
    private int total_line = 0;
    private static final int PALYING = 0;
    private static final int PAUSE = 1;
    private static final int GAMEOVER = 2;
    private int state;
    String[] show_state = {"P{PAUSE}", "C{CONTINUE}", "S{REPLAY}"};

    public static BufferedImage I;
    public static BufferedImage J;
    public static BufferedImage L;
    public static BufferedImage Z;
    public static BufferedImage O;
    public static BufferedImage T;
    public static BufferedImage S;
    public static BufferedImage bgImage;


    static {
        try {
            I = ImageIO.read(new File(imgPath + "1.png"));
            J = ImageIO.read(new File(imgPath + "2.png"));
            L = ImageIO.read(new File(imgPath + "3.png"));
            Z = ImageIO.read(new File(imgPath + "4.png"));
            O = ImageIO.read(new File(imgPath + "5.png"));
            T = ImageIO.read(new File(imgPath + "6.png"));
            S = ImageIO.read(new File(imgPath + "1.png"));
            bgImage = ImageIO.read(new File(imgPath + "bgImage.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void paint(Graphics g) {
        g.drawImage(bgImage, 0, 0, null);
        g.translate(22, 16);
        paintWall(g);
        paintCurrentOne(g);
        paintNextOne(g);
        paintScore(g);
        paintState(g);

    }

    private void paintState(Graphics g) {
        if(state == 0){
            g.drawString(show_state[0], 520, 650);
        }else if(state == 1){
            g.drawString(show_state[1], 520, 650);
        }else{
            g.drawString(show_state[2], 520, 650);
            g.setColor(Color.RED);
            g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 60));
            g.drawString("GAMEOVER", 40, 400);
        }
    }

    private void paintScore(Graphics g) {
        g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 30));
        g.drawString("SCORES: " + total_score, 520, 245);
        g.drawString("LINES : " + total_line, 520,  426);
    }

    private void paintCurrentOne(Graphics g){
        Cell[] cells =  currentOne.cells;
        for (Cell cell: cells) {
            int x = cell.getCol()*CELL_SIZE;
            int y = cell.getRow()*CELL_SIZE;
            g.drawImage(cell.getImage(), x, y, null);
        }
    }

    private void paintNextOne(Graphics g){
        Cell[] cells = nextOne.cells;
        for (Cell cell: cells) {
            int x = cell.getCol()*CELL_SIZE + 380;
            int y = cell.getRow()*CELL_SIZE + 20;
            g.drawImage(cell.getImage(), x, y, null);
        }
    }

    private void paintWall(Graphics g) {
        for (int i = 0; i < wall.length; i++) {
            for (int j = 0; j < wall[i].length; j++) {
                int x = j * CELL_SIZE;
                int y = i * CELL_SIZE;
                Cell cell = wall[i][j];
                if(cell == null){ g.drawRect(x, y, CELL_SIZE, CELL_SIZE);}
                else {g.drawImage(cell.getImage(), x, y, null);}

            }
        }
    }
    public boolean OutOfView(){
        Cell[] cells = currentOne.cells;
        for (Cell cell: cells){
            int col = cell.getCol();
            int row = cell.getRow();
            if(row < 0 || row > wall.length-1 || col < 0 || col > wall.length-1){
                return true;
            }
        }
        return false;
    }
    public boolean coincide(){
        Cell[] cells = currentOne.cells;
        for (Cell cell: cells){
            int row = cell.getRow();
            int col = cell.getCol();
            if(wall[row][col] != null){
                return true;
            }
        }
        return false;
    }
    public boolean canMove(int num){
        Cell[] cells =  currentOne.cells;
        for (Cell cell: cells){
            int x = cell.getRow() + num;
            if(x > wall.length-1 || x < 0) return false;
        }
        return true;
    }

    public void moveLeftAction(){
        if(canMove(-1) && !coincide() && !OutOfView()){
            currentOne.moveLeft();
        }
    }
    public void moveRightAction(){
        if(canMove(1) && !coincide() && !OutOfView()){
            currentOne.moveRight();
        }
    }
    public boolean isGameOver(){
        Cell[] cells = nextOne.cells;
        for(Cell cell: cells){
            int row = cell.getRow();
            int col = cell.getCol();
            if(wall[row][col] != null){
                return true;
            }
        }
        return false;
    }
     public void destroyLine(){
        int line = 0;
        Cell[] cells = currentOne.cells;
        for(Cell cell: cells){
            int row = cell.getRow();
            if(isFullLine(row)){
                line++;
                for (int i = row; i > 0; i--) {
                    System.arraycopy(wall[i-1], 0, wall[i], 0,wall[0].length);
                }
                wall[0] = new Cell[9];
            }
        }
        total_score += score_pool[line];
        total_line += line;
    }
    public boolean isFullLine(int row){
        Cell[] cells = wall[row];
        for (Cell cell: cells){
            if (cell == null) return false;
        }
        return true;
    }
    public boolean canDrop(){
        Cell[] cells = currentOne.cells;
        for(Cell cell: cells){
            int row = cell.getRow();
            int col = cell.getCol();
            if(row == wall.length-1){return false;}
            if(wall[row+1][col] != null){return false;}
        }
        return true;
    }
    public void sortDropAction(){
        if(canDrop()){
            currentOne.moveDrop();
        }else{
            landTowall();
            destroyLine();
            if(isGameOver()){
                state = GAMEOVER;
            }else {
                currentOne = nextOne;
                nextOne = Tetromino.RandomOn();
            }
        }
    }

    private void landTowall() {
        Cell[] cells = currentOne.cells;
        for(Cell cell: cells){
            int row = cell.getRow();
            int col = cell.getCol();
            wall[row][col] = cell;
        }
    }
    public void handDropAction(){
        while (true){
            if(canDrop()){
                currentOne.moveDrop();
            }else break;
        }
        landTowall();
        destroyLine();
        if(isGameOver()){
            state = GAMEOVER;
        }else {
            currentOne = nextOne;
            nextOne = Tetromino.RandomOn();
        }
    }
    public void rotateRightAction(){
        Tetromino Temp = currentOne;
        Temp.rotateRight();
        for(Cell cell: Temp.cells){
            int row = cell.getRow();
            int col = cell.getCol();
            if(row < 0 || row > wall.length-1 || col < 0 || col > wall.length-1){
                return;
            }else if(wall[row][col] != null){
                return;
            }
        }
        currentOne = Temp;
    }
    public void start(){
        state = PALYING;
        KeyListener l = new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                int code = e.getKeyCode();
                switch(code){
                    case KeyEvent.VK_DOWN:
                        sortDropAction();
                        break;
                    case KeyEvent.VK_RIGHT:
                        moveRightAction();
                        break;
                    case KeyEvent.VK_LEFT:
                        moveLeftAction();
                        break;
                    case KeyEvent.VK_UP:
                        rotateRightAction();
                        break;
                    case KeyEvent.VK_SPACE:
                        handDropAction();
                        break;
                    case KeyEvent.VK_C:
                        break;
                    case KeyEvent.VK_P:
                        if (state == PALYING) state = PAUSE;
                        break;
                    case KeyEvent.VK_S:
                        state = PALYING;
                        wall = new Cell[16][9];
                        currentOne = Tetromino.RandomOn();
                        nextOne =  Tetromino.RandomOn();
                        total_line = 0;
                        total_score = 0;
                        break;
                }
            }
        };
        this.addKeyListener(l);
        this.requestFocus();
        while (true){
            if(state == PALYING){
                try{
                    Thread.sleep(500);
                } catch (InterruptedException e){
                    e.printStackTrace();
                }
                if (canDrop()){
                    currentOne.moveDrop();
                }else {
                    landTowall();
                    destroyLine();
                    if(isGameOver()){
                        state = GAMEOVER;
                    }else {
                        currentOne = nextOne;
                        nextOne = Tetromino.RandomOn();
                    }
                }
            }
            repaint();
        }
    }
    public static void main(String[] args) {
        JFrame jf = new JFrame();
        Tetris panel = new Tetris();
        jf.add(panel);
        jf.setVisible(true);
        jf.setSize(810, 940);
//        jf.setLocationRelativeTo(null);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        panel.start();
    }
}
